Giới thiệu D3.js
Nội dung
- 1. Giới thiệu
- 2. Static Chart cơ bản
- 3. Attribute và Styling
- 4. Hover và Tooltip
- 5. Animation với Transition
- 6. Chain Rule trong D3
- 7. Kết luận
1. Giới thiệu
D3.js (Data-Driven Documents) là thư viện JavaScript giúp trực quan hóa dữ liệu trên web bằng SVG, HTML và CSS.
D3 cho phép gắn dữ liệu trực tiếp vào DOM, tạo biểu đồ, animation và tương tác linh hoạt.
SVG là chuẩn vẽ đồ họa vector trên web. Các phần tử như <rect>, <circle> hay <path> biểu diễn dữ liệu.
Ví dụ <path> dùng để vẽ đường cong hoặc shape phức tạp, tiện cho line chart hay area chart.
Với D3, chỉ cần gắn dữ liệu, các phần tử SVG sẽ tự động hiển thị đúng vị trí, kích thước và màu sắc theo số liệu. Trong bài này mình sẽ dùng dữ liệu mẫu như sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Dữ liệu mẫu
var data = [
{Country: "USA", Sales: 4800000},
{Country: "China", Sales: 4200000},
{Country: "Japan", Sales: 3100000},
{Country: "Germany", Sales: 2900000},
{Country: "India", Sales: 2500000},
{Country: "UK", Sales: 2200000}
];
var margin = {top: 30, right: 30, bottom: 70, left: 60},
width = 460 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
function makeSvg(target) {
return d3.select(target)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
}
2. Static Chart cơ bản
Phần khởi đầu của D3.js thường là biểu đồ tĩnh. Với vài dòng mã, bạn có thể biến mảng số liệu đơn giản thành biểu đồ cột SVG.
Ý tưởng chính:
- Dùng
d3.select()để chọn phần tử HTML/SVG. - Dùng
.data()để gắn dữ liệu vào các phần tử. - Dùng
.enter()để tạo các phần tử SVG mới (ví dụ:<rect>) tương ứng với dữ liệu.
Vẽ static chart với code sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
var svg1 = makeSvg("#chart-static");
var x1 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y1 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);
svg1.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x1(d.Country))
.attr("y", d => y1(d.Sales))
.attr("width", x1.bandwidth())
.attr("height", d => height - y1(d.Sales))
.attr("fill", "gray");
Khi mỗi cột tương ứng với một phần tử trong dữ liệu, ta đã có biểu đồ cơ bản đầu tiên.
3. Attribute và Styling trong D3
Sau khi gắn dữ liệu, D3 cho phép bạn tùy biến mọi thuộc tính của phần tử:
.attr()thay đổi thuộc tính SVG nhưx,y,width,height,fill, v.v..style()thay đổi CSS nhưopacity,stroke,font, v.v..text()thay đổi nội dung văn bản (thường dùng với<text>).
Thêm các thuộc tính cho chart bằng code sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var svg2 = makeSvg("#chart-attr");
var x2 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y2 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);
svg2.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x2));
svg2.append("g").call(d3.axisLeft(y2));
svg2.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x2(d.Country))
.attr("y", d => y2(d.Sales))
.attr("width", x2.bandwidth())
.attr("height", d => height - y2(d.Sales))
.attr("fill", "#69b3a2")
.attr("stroke", "black");
Khi kết hợp các hàm này, bạn có thể kiểm soát hoàn toàn cách dữ liệu hiển thị trên màn hình.
4. Hover và Hiển thị giá trị trên thanh
Để tăng tính tương tác, D3 hỗ trợ lắng nghe sự kiện như mouseover, mouseout…
Khi người dùng di chuột qua một thanh của biểu đồ, bạn có thể:
- Đổi màu thanh để nổi bật.
- Hiển thị giá trị trực tiếp trên thanh (thay vì tooltip) với font nhỏ gọn.
Đoạn code sau chỉnh sửa thuộc tính hover cho chart:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var svg3 = makeSvg("#chart-hover");
var x3 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y3 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);
svg3.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x3));
svg3.append("g").call(d3.axisLeft(y3));
// thêm label text (ẩn ban đầu)
var labels = svg3.selectAll(".label")
.data(data)
.enter()
.append("text")
.attr("x", d => x3(d.Country) + x3.bandwidth()/2)
.attr("y", d => y3(d.Sales) - 5)
.attr("text-anchor", "middle")
.attr("fill", "#000")
.style("font-size", "10px")
.text("");
svg3.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x3(d.Country))
.attr("y", d => y3(d.Sales))
.attr("width", x3.bandwidth())
.attr("height", d => height - y3(d.Sales))
.attr("fill", "#4CAF50")
.on("mouseover", function(d, i) {
d3.select(this).attr("fill", "#2E7D32");
labels.filter((l, j) => i === j)
.text("$" + d.Sales.toLocaleString());
})
.on("mouseout", function(d, i) {
d3.select(this).attr("fill", "#4CAF50");
labels.filter((l, j) => i === j)
.text("");
});
Kỹ thuật này giúp biểu đồ tương tác mà không phụ thuộc vào tooltip, tránh các vấn đề hiển thị trên các theme hoặc Jekyll.
Bạn có thể dùng mouseover/mouseout để cập nhật text trên thanh và đổi màu thanh mượt mà.
5. Animation với Transition
D3 cung cấp cơ chế animation tích hợp thông qua .transition() và .duration().
Điều này giúp bạn dễ dàng tạo hiệu ứng:
- Cột “mọc lên” khi hiển thị.
- Đường di chuyển mượt mà khi dữ liệu thay đổi.
- Màu sắc dần biến đổi theo giá trị.
Đoạn code mẫu sau tạo animation cho chart:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var svg4 = makeSvg("#chart-anim");
var x4 = d3.scaleBand().range([0, width]).domain(data.map(d => d.Country)).padding(0.2);
var y4 = d3.scaleLinear().domain([0, 5000000]).range([height, 0]);
svg4.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x4));
svg4.append("g").call(d3.axisLeft(y4));
function drawAnimation() {
svg4.selectAll("rect").remove();
svg4.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x4(d.Country))
.attr("y", y4(0))
.attr("width", x4.bandwidth())
.attr("height", height - y4(0))
.attr("fill", "#2196F3")
.transition()
.duration(800)
.attr("y", d => y4(d.Sales))
.attr("height", d => height - y4(d.Sales))
.delay((d,i) => i * 200);
}
// vẽ lần đầu
drawAnimation();
d3.select("#chart-anim")
.append("button")
.text("Replay")
.style("margin-top", "10px")
.on("click", drawAnimation);
Bạn có thể thêm .delay() để tạo hiệu ứng tuần tự giữa các phần tử, giúp biểu đồ “sống” hơn.
6. Chain Rule trong D3
Một điểm nổi bật của D3 là chaining — các hàm có thể nối tiếp nhau trên cùng một dòng.
Ví dụ: từ việc chọn phần tử → gán dữ liệu → đặt thuộc tính → thêm animation, tất cả đều liên kết liền mạch.
Điều này giúp mã ngắn gọn, dễ đọc và thể hiện rõ “luồng xử lý” của D3.
7. Kết luận
- D3.js là công cụ mạnh mẽ giúp biến dữ liệu thành hình ảnh động.
- Bắt đầu từ biểu đồ tĩnh, bạn có thể mở rộng với tương tác, animation và các biểu đồ phức tạp hơn (line chart, scatter plot, network…).
- Hiểu rõ các khái niệm data binding, enter-update-exit, attribute, và chaining là nền tảng để làm chủ D3.js.
- Những nội dung trên chỉ là sơ bộ, để hiểu rõ hơn bạn nên tham khảo trang web chính thức của D3.js hoặc các sách chuyên sâu về D3 “Interactive Data Visualization for the Web” của Scott Murray.